#pragma once
#include "..\dxstdafx.h"
#include <vector>
#include "..\EventManager.h"
#include "Input.h"
#include "..\utils\Logger.h"
#include "..\renderer\Renderer.h"
#include "..\statemanager\GameStateManager.h"
#include "..\audio\AudioManager.h"
#include "Settings.h"
#include "DrawCounter.h"
#include "..\renderer\Viewport.h"
//#include "..\game\GameComponent.h"
//#include "..\game\ComponentManager.h"
#include "..\pipeline\DeclarationManager.h"
#include "..\action\ActionManager.h"
#include "..\utils\mtrand.h"

namespace ds {

struct GameTime {
	double total;
	double delta;
	double alpha;
};

class Renderer;
class AudioManager;
class Service;
class KeyboardController;
class MouseController;
class DebugRenderer;
class ResManager;
class World;
class PhysicalWorld;
class CollisionDetector;

class Engine {

typedef std::vector<KeyboardController*> ControllerList;
typedef std::vector<MouseController*> MouseControllerList;
typedef std::vector<Service*> Services;

public:
	Engine();	
	~Engine();
	void updateFrame(float elapsedTime);
	void init(HWND hWnd,const Settings& settings,Rect wndPosition);
	// objects
	EventManager& getEventManager() {
		return *m_EventManager;
	}	
	DeclarationManager& getDeclarationManager() {
		return *m_DeclarationManager;
	}
	CollisionDetector& getCollisionDetector() {
		return *m_CollisionDetector;
	}
	ResManager& getResourceManager() {
		return *m_ResourceManager;
	}
	World& getWorld() {
		return *m_World;	
	}
	ActionManager& getActionManager() {
		return *m_ActionManager;
	}
	Renderer* getRenderer();
	AudioManager& getAudioManager() {
		return *m_Audio;
	}
	Input* getInput();
	Viewport* getViewport() { return m_Viewport; }
	DrawCounter* getDrawCounter() { return m_DrawCounter; }
	DebugRenderer* getDebugRenderer() { return m_DebugRenderer; }
	LPDIRECT3DDEVICE9 getDevice();
	void OnKeyDown( WPARAM wParam );
	void OnKeyUp( WPARAM wParam );
	void OnChar(char ascii,unsigned int keyState);
	void onButtonDown(int button) {
		m_ButtonDown = button;
	}
	void onButtonUp(int button) {
		m_ButtonUp = button;
	}
	void addController(KeyboardController *controller);
	void addMouseController(MouseController *controller);
	void setMousePosition(POINTS mp) { 
		mousePosition = mp;		
	}
	Vec2 getMousePosition() const { 
		return Vec2(mousePosition.x,mousePosition.y);
	}
	int getMousePosX() const { 
		return mousePosition.x;
	}
	int getMousePosY() const { 
		return mousePosition.y;
	}
	void toggleUpdateAllowed() { updateAllowed = !updateAllowed;}
	bool isUpdateAllowed() const { 
		return updateAllowed;
	}
	Rect getWindowPosition() const { 
		return windowPosition;
	}
	// main function
	const float getElapsedTime() const { 
		return m_ElapsedTime; 
	}
	void buildFrame(float elapsedTime);

	void initializeComponents();
	void initializeNodes();

	void shutdown();
	// services
	void addService(Service *service);
	Service* getService(const std::string& name);
	
	int getWidth() { return width;}
	int getHeight() { return height;}
	void createViewport(int width,int height);	
	RenderMode getRenderMode() { return m_Renderer->getRenderMode(); }
	//
	bool isInitialized() const {
		return m_Initialized;
	}
	// game state management
	void addGameState(GameState *gameState) {
		m_GameStateManager->addGameState(gameState);
	}
	void activateGameState(const std::string& name) {
		m_NextState = name;
	}
	GameState* getActiveState() {
		return m_GameStateManager->getActiveState();
	}
	GameState* getGameState(const std::string& name) {
		return m_GameStateManager->get(name);
	}
	const bool isGameStateActive(const std::string& name) const {
		return m_GameStateManager->isActive(name);
	}
	void initializeStates() {
		m_GameStateManager->initializeStates(*m_ResourceManager);
	}
	//
	void finalizeInitialisation() {
		if ( !m_ActivateState.empty() ) {
			m_GameStateManager->activate(m_ActivateState);
			m_ActivateState = "";
		}
		m_Initialized = true;
	}
	void debug();
	//
	float random(float min,float max) {
		return min + (max - min)* (float)rand();
	}	
	HWND getHWND() {
		return m_hWnd;
	}
private:
	// process buttons
	void processButtons();
	//
	EventManager* m_EventManager;			
	ResManager* m_ResourceManager;
	HWND m_hWnd;
	Renderer *m_Renderer;
	GameStateManager *m_GameStateManager;
	Input *m_Input;
	AudioManager *m_Audio;
	Viewport* m_Viewport;
	World* m_World;
	ActionManager* m_ActionManager;
	CollisionDetector* m_CollisionDetector;
	DebugRenderer* m_DebugRenderer;
	ControllerList controllers;
	MouseControllerList mouseController;
	DeclarationManager* m_DeclarationManager;
	POINTS mousePosition; 
	bool updateAllowed;
	Rect windowPosition;
	Services m_Services;
	int mode;
	int width;
	int height;
	DrawCounter *m_DrawCounter;
	float m_ElapsedTime;
	bool m_Initialized;
	std::string m_ActivateState;
	std::string m_NextState;
	// FIXME: extract to MouseManager
	int m_ButtonDown;
	int m_ButtonUp;
	MTRand_open rand;
};

};
extern ds::Engine *gEngine;
